﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using Algorithms;

namespace Algorithms
{
    public class Genome
    {
        #region Fields

        private int[] _genes;

        #endregion // Fields

        #region Constructor

        /// <summary>
        /// Constructs a new genome with x genes
        /// </summary>
        /// <param name="length"></param>
        public Genome(int length)
        {
            _genes = new int[length];
        }

        #endregion // Constructor

        #region Properties

        public int Length { get { return _genes.Length; } }

        public int[] Genes { get { return _genes; } }

        #endregion // Properties

        #region Methods

        public void Mutate(double rate)
        {
            for (int index = 0; index < Length; index++)
            {
                double randomSample = ThreadSafeContainer<Random>.Instance.NextDouble();
                if (randomSample < rate)
                {
                    double manipularRate = ThreadSafeContainer<Random>.Instance.NextDouble();
                    unchecked
                    {
                        // Go into unchecked mode since we want to support overflowing 
                        _genes[index] = (int)(_genes[index] * (manipularRate * 2));
                    }
                }
            }
        }

	                    
        public void Crossover(Genome other, out Genome child1, out Genome child2)
        {
            int length = Length;
            double crossOverRate = ThreadSafeContainer<Random>.Instance.NextDouble();
            int crossOverIndex = (int)(length * crossOverRate);

            child1 = new Genome(length);
            child2 = new Genome(length);

            for (int index = 0; index < crossOverIndex; index++)
            {
                child1._genes[index] = this._genes[index];
                child2._genes[index] = other._genes[index];
            }

            for (int index = crossOverIndex; index < length; index++)
            {
                child1._genes[index] = other._genes[index];
                child2._genes[index] = this._genes[index];
            }
        }

        /// <summary>
        /// Scrambles the genome with random data
        /// </summary>
        public void Scramble()
        {
            for (int index = 0; index < Length; index++)
            {
                Genes[index] = ThreadSafeContainer<Random>.Instance.Next();
            }
        }

        #endregion // Methods      
    }
}
